package server

import (
	"fmt"
	"net"
	"strings"
	"time"
)

/*
Client 在线用户结构体
*/
type Client struct {
	C    chan string //用户发送数据的管道
	Name string
	Addr string
}

// 保存在线的用户  cliaddr
var onlineMap map[string]Client

var message = make(chan string)

/*
Manager 给在线客户端广播消息
*/
func Manager() {

	for {
		msg := <-message
		//遍历map，给map中的每一个成员发送上线信息
		for _, cli := range onlineMap {
			cli.C <- msg

		}
	}
}

// WriteMsgToClient 给客户端发送消息
func WriteMsgToClient(cli Client, conn net.Conn) {
	for msg := range cli.C { //给当前客户端发送消息
		conn.Write([]byte(msg + "\n"))

	}
}

// MakeMsg 组装消息
func MakeMsg(cli Client, msg string) (buf string) {
	buf = "[" + cli.Addr + "]" + cli.Name + ": " + msg
	return buf
}

//HandleConn 处理用户连接
func HandleConn(conn net.Conn) {
	defer conn.Close()

	cliAddr := conn.RemoteAddr().String()

	cli := Client{make(chan string), cliAddr, cliAddr}

	onlineMap[cliAddr] = cli

	//新开一个协程，专门给当前客户端发送信息
	go WriteMsgToClient(cli, conn)

	//广播某个在线的消息
	// message <- "[" + cli.Addr + "]" + cli.Name + ": Login"
	message <- MakeMsg(cli, "Login")

	cli.C <- MakeMsg(cli, "I am here")

	isQuit := make(chan bool)  //对方是否在线
	hasData := make(chan bool) // 客户端是否有数据

	//接受用户发来的消息
	go func() {
		buf := make([]byte, 2048)
		for {
			n, err := conn.Read(buf)
			if n == 0 { //对方断开，或者出问题
				isQuit <- true

				fmt.Println("conn.Read err = ", err)
				return
			}

			msg := string(buf[:n-1]) //windows nc.exe ，多一个换行

			if len(msg) == 3 && msg == "who" {
				//遍历map，给当前用户发送所有成员名字Name
				conn.Write([]byte("user list:\n"))
				for _, tmp := range onlineMap {
					msg = tmp.Addr + ":" + tmp.Name + "\n"
					conn.Write([]byte(msg))
				}
			} else if len(msg) >= 8 && msg[:6] == "rename" {
				// rename|make 改名字
				name := strings.Split(msg, "|")[1]
				cli.Name = name
				onlineMap[cliAddr] = cli
				conn.Write([]byte("rename OK\n"))

			} else if len(msg) == 3 && msg == "bye" {
				// 主动say bye
				message <- MakeMsg(cli, msg)
				isQuit <- true

			} else {
				//转发此内容
				message <- MakeMsg(cli, msg)
			}
			hasData <- true
		}
	}()

	for {
		//select检测channel的流动
		select {
		case <-isQuit:
			delete(onlineMap, cliAddr) //当前用户从map移除
			message <- MakeMsg(cli, "login out")
			return
		case <-hasData:

		case <-time.After(60 * time.Second): //
			delete(onlineMap, cliAddr) //当前用户从map移除
			message <- MakeMsg(cli, "timeout to leave")
			return
		}
	}

}

// Server 服务端主函数
func Server() {
	//给map分配空间
	onlineMap = make(map[string]Client)

	//监听
	listener, err := net.Listen("tcp", "127.0.0.1:8000")
	if err != nil {
		fmt.Println("net.Listen err = ", err)
		return
	}

	go Manager()

	defer listener.Close() //延迟关闭
	for {
		conn, err := listener.Accept()
		if err != nil {
			fmt.Println("listener.Accept err= ", err)
			continue

		}

		go HandleConn(conn)

	}

}
